`timescale 1ns / 1ps

module dwc_layer
#(
    parameter N_INW     = 16,
    parameter N_ACT     = 2,
    parameter N_CH      = 1280,
    parameter COL       = 40,
    parameter ROW       = 20,
    parameter BIT_IN    = 8,
    parameter BIT_WT    = 5,
    parameter BIT_CV    = 16,
    parameter BIT_NB    = 16,
    parameter BIT_NM    = 16,
    parameter BIT_OT    = 8,
    parameter PADVAL    = 0,
    // dwc weight ROM
    parameter DWCV_PE    = "DSP",
    parameter DWET_FILE  = "L10_DW.mem",
    parameter DWET_TYPE  = "block",
    parameter DWET_LATENCY = 2,
    // im2col buffer RAM
    parameter DBUF_TYPE  = "block",
    parameter DBUF_LATENCY = 2,
    // norm weight ROM
    parameter NORM_PE    = "DSP",
    parameter NORM_FILE  = "L10_BM.mem",
    parameter NORM_TYPE  = "block",
    parameter NORM_LATENCY = 2
)
(
    input   clk,
    input   rst,
    
    input   i_vld,
    output  i_rdy,
    input   [N_INW * BIT_IN -1 : 0]    i_data,
    
    output  o_vld,
    input   o_rdy,
    output  [N_ACT * BIT_OT -1 : 0]    o_data
);

wire dwc_vld, dwc_rdy;
wire [N_INW * BIT_CV-1 : 0] dwc_data;

dwc #(
    .N_IO        ( N_INW        ),
    .N_CH        ( N_CH         ),
    .COL         ( COL          ),
    .ROW         ( ROW          ),
    .BIT_I       ( BIT_IN       ),
    .BIT_W       ( BIT_WT       ),
    .BIT_O       ( BIT_CV       ),
    .PADVAL      ( PADVAL       ),
    .PE_TYPE     ( DWCV_PE      ),
    .ROM_FILE    ( DWET_FILE    ),
    .ROM_TYPE    ( DWET_TYPE    ),
    .ROM_LATENCY ( DWET_LATENCY ),
    .RAM_TYPE    ( DBUF_TYPE    ),
    .RAM_LATENCY ( DBUF_LATENCY )
)
inst_dwc (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   ( i_rdy    ),
    .i_vld                   ( i_vld    ),
    .i_data                  ( i_data   ),

    .o_rdy                   ( dwc_rdy  ),
    .o_vld                   ( dwc_vld  ),
    .o_data                  ( dwc_data )
);

wire rdu_vld, rdu_rdy;
wire [N_ACT * BIT_CV -1 : 0] rdu_data;

reduce2 #(
    .N      ( N_INW / N_ACT  ),
    .WIDTH  ( N_ACT * BIT_CV )
)
inst_reduce (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   ( dwc_rdy  ),
    .i_vld                   ( dwc_vld  ),
    .i_data                  ( dwc_data ),

    .o_rdy                   ( rdu_rdy  ),
    .o_vld                   ( rdu_vld  ),
    .o_data                  ( rdu_data )
);

wire skd_vld, skd_rdy;
wire [N_ACT * BIT_CV -1 : 0] skd_data;

hs_fifo2 #(
    .WIDTH  ( N_ACT * BIT_CV    )
) inst_skid (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   ( rdu_rdy  ),
    .i_vld                   ( rdu_vld  ),
    .i_data                  ( rdu_data ),

    .o_rdy                   ( skd_rdy  ),
    .o_vld                   ( skd_vld  ),
    .o_data                  ( skd_data )
);

wire act_vld, act_rdy;
wire [N_ACT * BIT_OT -1 : 0] act_data;

norm_actv #(
    .N_IO       ( N_ACT  ),
    .N_CH       ( N_CH   ),
    .N_BK       ( 0      ),
    .N_RP       ( 1      ),
    .BIT_I      ( BIT_CV ),
    .BIT_B      ( BIT_NB ),
    .BIT_M      ( BIT_NM ),
    .BIT_O      ( BIT_OT ),
    .RSHIFT     ( 16     ),
    .PE_TYPE    ( NORM_PE ),
    .ROM_FILE   ( NORM_FILE ),
    .ROM_TYPE   ( NORM_TYPE ),
    .ROM_LATENCY( NORM_LATENCY )
) inst_norm_actv
(
    .clk        (clk),
    .rst        (rst),

    .i_vld      (skd_vld),
    .i_rdy      (skd_rdy),
    .i_data     (skd_data),

    .o_vld      (act_vld),
    .o_rdy      (act_rdy),
    .o_data     (act_data)
);

assign act_rdy = o_rdy;
assign o_vld = act_vld;
assign o_data = act_data;

endmodule
